package com.bbcare.oms.plat.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bbcare.comm.DateUtil;
import com.bbcare.comm.SeqUtil;
import com.bbcare.comm.ToolUtil;
import com.bbcare.oms.plat.entity.Account;
import com.bbcare.oms.plat.entity.AccountApplication;
import com.bbcare.oms.plat.entity.Application;
import com.bbcare.oms.plat.entity.AuAccountRoleRel;
import com.bbcare.oms.plat.entity.AuHospital;
import com.bbcare.oms.plat.entity.AuProjectRoleRel;
import com.bbcare.oms.plat.entity.AuRoleMenuAuth;
import com.bbcare.oms.plat.entity.AuTenantDeptRel;
import com.bbcare.oms.plat.entity.Auth;
import com.bbcare.oms.plat.entity.Group;
import com.bbcare.oms.plat.entity.IaLoginoprRecord;
import com.bbcare.oms.plat.entity.ResourceVersion;
import com.bbcare.oms.plat.entity.Role;
import com.bbcare.oms.plat.entity.Tenant;
import com.bbcare.oms.plat.service.IAccountService;
import com.bbcare.oms.plat.store.ibatis.IALoginOprDAO;
import com.bbcare.oms.plat.store.ibatis.IAccountApplicationDAO;
import com.bbcare.oms.plat.store.ibatis.IAccountDAO;
import com.bbcare.oms.plat.store.ibatis.IApplicationDAO;
import com.bbcare.oms.plat.store.ibatis.IAuAccountRoleRelDAO;
import com.bbcare.oms.plat.store.ibatis.IAuHospitalDAO;
import com.bbcare.oms.plat.store.ibatis.IAuProjectRoleRelDAO;
import com.bbcare.oms.plat.store.ibatis.IAuRoleMenuAuthDAO;
import com.bbcare.oms.plat.store.ibatis.IAuTenantDeptRelDAO;
import com.bbcare.oms.plat.store.ibatis.IAuthDAO;
import com.bbcare.oms.plat.store.ibatis.IResourceVersionDAO;
import com.bbcare.oms.plat.store.ibatis.ITenantDAO;
import com.bbcare.oms.plat.store.ibatis.extend.ExtendDAO;
import com.bbcare.oms.plat.store.redis.AccountRDS;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import redis.clients.jedis.JedisPool;


@Service
public class AccountService implements IAccountService {
    private final static Log logger = LogFactory.getLog(AccountService.class);

    @Autowired
    private IAccountDAO accountDAO;
    @Autowired
    private IAuthDAO authDAO;
    @Autowired
    private ITenantDAO tenantDAO;
    @Autowired
    private IApplicationDAO applicationDAO;
    @Autowired
    private IResourceVersionDAO resourceVersionDAO;
    @Autowired
    private IAccountApplicationDAO accountApplicationDAO;
    @Autowired
    private IAuAccountRoleRelDAO auAccountRoleRelDAO;
    @Autowired
    private IAuProjectRoleRelDAO iAuProjectRoleRelDAO;
    @Autowired
    private IAuRoleMenuAuthDAO iAuRoleMenuAuthDAO;
    @Autowired
    private IAuTenantDeptRelDAO iAuTenantDeptRelDAO;
    @Autowired
    private IALoginOprDAO iALoginOprDAO;
    @Autowired
    private IAuHospitalDAO auHospitalDao;

    @Autowired
    private ExtendDAO extendDAO;

    @Autowired
    protected JedisPool jedisPool;

    public List<Account> getAccounts(int page, int rows)
            throws Exception {
        page = page == 0 ? 1 : page;
        rows = rows == 0 ? 10 : rows;
        return this.accountDAO.query((page - 1) * rows, rows);
    }

    public Account doLogin(String username, String password, String ipaddress) throws Exception {
        logger.debug("Begin to doLogin.");
        password = ToolUtil.Encrept(password);
        List<Account> list = this.accountDAO.getAccountByUsername(username);

        if ((list != null) && (list.size() > 0)) {
            logger.info("list size>0");
            Account account = (Account) list.get(0);
            if (password.endsWith(account.getPassword())) {
                logger.info("begin to operate RDS.");
                AccountRDS rds = new AccountRDS(this.jedisPool);
                String sessionID = UUID.randomUUID().toString();
                account.setSessionID(sessionID);
                account.setPassword(null);
                account = getApplications(account);
                account = getCurrNavbarAuth(account, ipaddress);
                AccountApplication accountApplication = account.getApps().get(0);
                if(accountApplication.getTenantId() != null){
                    Tenant tenant = tenantDAO.select(accountApplication.getTenantId());
                    if(tenant.getRefTenantId() != null && !tenant.getRefTenantId().equals("")){
                        account.setRefTenantId(tenant.getRefTenantId());
                    }
                }
                rds.add(sessionID, account);
                logger.info("return a account");
                return account;
            }
            throw new Exception("您输入的密码不正确~！");
        }
        throw new Exception("账号错误或者不存在~！");
    }

    @Override
    public Account autologin(String username, String ipaddress) throws Exception {
        List<Account> list = this.accountDAO.getAccountByUsername(username);
        if ((list != null) && (list.size() > 0)) {
            Account account = list.get(0);
            AccountRDS rds = new AccountRDS(this.jedisPool);
            String sessionID = UUID.randomUUID().toString();
            account.setSessionID(sessionID);
            account.setPassword(null);
            account = getApplications(account);
            account = getCurrNavbarAuth(account, ipaddress);
            rds.add(sessionID, account);
            return account;
        }
        throw new Exception("账号不存在！");
    }

    public void doLogout(String sessionID)
            throws Exception {
        AccountRDS rds = new AccountRDS(this.jedisPool);
        rds.remove(sessionID);
    }

    @Override
    public Account getRedis(String sessionID) throws Exception {
        AccountRDS rds = new AccountRDS(this.jedisPool);
        return JSON.parseObject(rds.get(sessionID).toString(), Account.class);
    }

    public Account switchApp(String appId, Account account, String ipaddress) throws Exception {
        List<AccountApplication> apps = this.accountApplicationDAO.queryByAccountId(account.getId());
        boolean tag = false;
        for (AccountApplication app : apps) {
            if (appId.equals(app.getId())) {
                tag = true;
                break;
            }
        }
        if (!tag) {
            throw new Exception("需要切换的应用不存在！");
        }
        for (AccountApplication app : apps) {
            Tenant tenant = this.tenantDAO.select(app.getTenant().getId());
            IaLoginoprRecord opr = null;
            if (appId.equals(app.getId())) {
                this.accountApplicationDAO.updateStatus(appId, 1);
                if (!"1".equals(tenant.getVersion())) {
                    String roleId = app.getRole().getId();
                    List<Auth> list = this.authDAO.getNavbarAuthByRole(roleId);
                    list = getNavbarAuthByParent(list,roleId);
                    app.setNavbars(list);
                    app.setSystemFlag("2");

                    String accountId = app.getAccount().getId();

                    String tenantId = app.getTenant().getId();
                    String currTime = DateUtil.getTimeString(DateUtil.getSysDateA());
                    String id = SeqUtil.getSeqNo("00");
                    opr = new IaLoginoprRecord();
                    opr.setId(id);
                    opr.setCreateAuthor("");
                    opr.setCreateTime(currTime);
                    opr.setUpdateAuthor("");
                    opr.setUpdateTime(currTime);
                    opr.setAccountId(accountId);
                    opr.setIpAddress(ipaddress);
                    opr.setRemark("");
                    opr.setRoleId(roleId);
                    opr.setProjectId("");
                    opr.setTenantId(tenantId);
                    opr.setAppId(appId);

                    this.iALoginOprDAO.insertLoginopr(opr);
                }
                app.setStatus(1);
                account.setType(app.getAccountType());
                account.setRelationId(app.getAccountRelationId());
            } else if (app.getStatus() == 1) {
                this.accountApplicationDAO.updateStatus(app.getId(), 2);
                app.setStatus(2);
            }
            if ("1".equals(tenant.getVersion())) {
                app.setAuProjectRoleRel(this.iAuProjectRoleRelDAO.selectPoject(account.getId(), app.getTenant().getId()));
                if (app.getAuProjectRoleRel() != null) {
                    List<AuProjectRoleRel> list = app.getAuProjectRoleRel();
                    for (int i = 0; i < list.size(); i++) {
                        opr = this.iALoginOprDAO.queryByroleId(((AuProjectRoleRel) list.get(i)).getId(), tenant.getId());
                        if (opr != null) {
                            ((AuProjectRoleRel) list.get(i)).setLoginTime(opr.getUpdateTime());
                        } else {
                            ((AuProjectRoleRel) list.get(i)).setLoginTime(DateUtil.getDateA(new Date()));
                        }
                    }
                    app.setAuProjectRoleRel(list);
                }
                app.setSystemFlag("1");
                app.setTenantRootGroupIdList(this.iAuTenantDeptRelDAO.select(app.getTenant().getId(), "1"));
            } else {
                opr = this.iALoginOprDAO.queryByroleId(app.getRole().getId(), tenant.getId());
                if (opr != null) {
                    app.setLoginTime(opr.getUpdateTime());
                } else {
                    app.setLoginTime(DateUtil.getDateA(new Date()));
                }
            }
            loadAppAndTenantInfo(app);
            clearAccountApplicationRelation(app);
        }
        account.setApps(apps);

        AccountRDS rds = new AccountRDS(this.jedisPool);
        rds.remove(account.getSessionID());
        String sessionID = UUID.randomUUID().toString();
        account.setSessionID(sessionID);
        rds.add(sessionID, account);

        // 新增权限字段 2023.04.09 by Ace
        String role = extendDAO.selectRoleByAccountId(account.getId());
        if (role== null || "".equals(role)){
            role = "";
        }
        account.setRole(role);

        return account;
    }




    private void loadAppAndTenantInfo(AccountApplication aa)
            throws Exception {
        Application app = this.applicationDAO.select(aa.getApp().getId());
        final String tenantId = aa.getTenant().getId();
        logger.debug("++++tenantId:"+tenantId);
        Tenant tenant = this.tenantDAO.select(tenantId);
        AuHospital auHospital = selectHospital(tenant);
        aa.setAppAlias(app.getAlias());
        aa.setTenantId(tenant.getId());
        aa.setTenantName(tenant.getName());
        aa.setTenantIcon(tenant.getIcon());
        aa.setTenantType(tenant.getType());
        aa.setTenantRootGroupId(tenant.getRootGroup().getId());
        aa.setSystemFlag(tenant.getVersion());
        aa.setAuHospital(auHospital);
    }


    private void clearAccountApplicationRelation(AccountApplication aa) {
        aa.setApp(null);
        aa.setRole(null);
        aa.setTenant(null);
        aa.setAccount(null);
    }


    private Account getApplications(Account account)
            throws Exception {
        List<AccountApplication> list = this.accountApplicationDAO.queryByAccountId(account.getId());
        account.setApps(list);
        IaLoginoprRecord opr = null;
        for (int i = 0; i < list.size(); i++) {
            loadAppAndTenantInfo((AccountApplication) list.get(i));

            if ("1".equals(((AccountApplication) list.get(i)).getSystemFlag())) {
                ((AccountApplication) list.get(i)).setAuProjectRoleRel(this.iAuProjectRoleRelDAO.selectPoject(account.getId(), ((AccountApplication) list.get(i)).getTenant().getId()));
                ((AccountApplication) list.get(i)).setTenantRootGroupIdList(this.iAuTenantDeptRelDAO.select(((AccountApplication) list.get(i)).getTenant().getId(), "1"));
                if (((AccountApplication) list.get(i)).getAuProjectRoleRel() != null) {
                    List<AuProjectRoleRel> lists = ((AccountApplication) list.get(i)).getAuProjectRoleRel();
                    for (int j = 0; j < lists.size(); j++) {
                        opr = this.iALoginOprDAO.queryByroleId(((AuProjectRoleRel) lists.get(j)).getId(), ((AccountApplication) list.get(i)).getTenant().getId());
                        if (opr != null) {
                            ((AuProjectRoleRel) lists.get(j)).setLoginTime(opr.getUpdateTime());
                        } else {
                            ((AuProjectRoleRel) lists.get(j)).setLoginTime(DateUtil.getDateA(new Date()));
                        }
                    }
                    ((AccountApplication) list.get(i)).setAuProjectRoleRel(lists);
                }
            } else {
                opr = this.iALoginOprDAO.queryByroleId(((AccountApplication) list.get(i)).getRole().getId(), ((AccountApplication) list.get(i)).getTenant().getId());
                if (opr != null) {
                    ((AccountApplication) list.get(i)).setLoginTime(opr.getUpdateTime());
                } else {
                    ((AccountApplication) list.get(i)).setLoginTime(DateUtil.getDateA(new Date()));
                }
            }
            if (((AccountApplication) list.get(i)).getStatus() == 1) {
                account.setType(((AccountApplication) list.get(i)).getAccountType());
                account.setRelationId(((AccountApplication) list.get(i)).getAccountRelationId());
                account = getCurrAction(account);
            }
        }
        return account;
    }


    private Account getCurrNavbarAuth(Account account, String ipaddress)
            throws Exception {
        if (account.getApps() == null) {
            return account;
        }
        for (AccountApplication aa : account.getApps()) {
            if (aa.getStatus() == 1) {
                if (!"1".equals(aa.getSystemFlag())) {


                    String roleId = aa.getRole().getId();

                    String accountId = aa.getAccount().getId();

                    String tenantId = aa.getTenantId();

                    String appId = aa.getId();
                    String currTime = DateUtil.getTimeString(DateUtil.getSysDateA());
                    String id = SeqUtil.getSeqNo("00");
                    IaLoginoprRecord opr = new IaLoginoprRecord();
                    opr.setId(id);
                    opr.setCreateAuthor("");
                    opr.setCreateTime(currTime);
                    opr.setUpdateAuthor("");
                    opr.setUpdateTime(currTime);
                    opr.setAccountId(accountId);
                    opr.setIpAddress(ipaddress);
                    opr.setRemark("");
                    opr.setRoleId(roleId);
                    opr.setProjectId("");
                    opr.setTenantId(tenantId);
                    opr.setAppId(appId);

                    this.iALoginOprDAO.insertLoginopr(opr);
                    List<Auth> list = this.authDAO.getNavbarAuthByRole(aa.getRole().getId());
                    aa.setNavbars(list);
                    list = getNavbarAuthByParent(list,roleId);
                }
            }
            clearAccountApplicationRelation(aa);
        }
        return account;
    }

    private List<Auth> getNavbarAuthByParent(List<Auth> list, String roleId) throws Exception {
        if (list == null) {
            return null;
        }
        for (Auth auth : list) {
            List<Auth> auths = getNavbarAuthByParent(this.authDAO.getNavbarAuthByParent(auth.getId(),roleId),roleId);
            if (auth.getResource() != null) {
                auth.setResource(this.resourceVersionDAO.select(auth.getResource().getId()));
            }
            auth.setChildrens(auths);
        }
        return list;
    }

    //private List<Auth> getNavbarAuthByParent(List<Auth> list)
    //        throws Exception {
    //    if (list == null) {
    //        return null;
    //    }
    //    for (Auth auth : list) {
    //        List<Auth> auths = getNavbarAuthByParent(this.authDAO.getNavbarAuthByParent(auth.getId()));
    //        if (auth.getResource() != null) {
    //            auth.setResource(this.resourceVersionDAO.select(auth.getResource().getId()));
    //        }
    //        auth.setChildrens(auths);
    //    }
    //    return list;
    //}


    private Account getCurrAction(Account account)
            throws Exception {
        return account;
    }


    public Map<String, Object> switchProject(String appId, String projectId, Account account, String sessionID, String ipaddress)
            throws Exception {
        Map<String, Object> mapOut = new HashMap();
        List<AuAccountRoleRel> list = selectAuAccountRoleRel(account, projectId);

        AccountRDS rds = new AccountRDS(this.jedisPool);
        if (CollectionUtils.isEmpty(list)) {
            throw new Exception("没有查询到当前账号角色权限信息！");
        }
        if (list.size() == 1) {
            AuAccountRoleRel auRel = (AuAccountRoleRel) list.get(0);
            AuProjectRoleRel RoleRel = selectAuProjectRoleRel(auRel.getRoleId(), projectId);
            if (RoleRel == null) {
                throw new Exception("没有查询到当前项目角色权限信息！");
            }
            List<Auth> lists = this.authDAO.getNavbarAuthByRole(RoleRel.getId());
            lists = getNavbarAuthByParent(lists,RoleRel.getId());
            mapOut.put("navbars", lists);
            String json = (String) rds.get(sessionID);
            if (StringUtils.isEmpty(json)) {
                throw new Exception("session已经失效，请重新登录！");
            }
            Map<String, Object> map = new HashMap();
            map.put("json", json);
            map.put("projectId", projectId);
            map.put("appId", appId);
            String jsons = resolveJson(map);
            int time = 3600;
            rds.setredis(sessionID, jsons);
            rds.Expire(sessionID, time);


            String roleId = RoleRel.getId();

            String accountId = account.getId();

            String tenantId = RoleRel.getTenantId();
            String currTime = DateUtil.getTimeString(DateUtil.getSysDateA());
            String id = SeqUtil.getSeqNo("00");
            IaLoginoprRecord opr = new IaLoginoprRecord();
            opr.setId(id);
            opr.setCreateAuthor("");
            opr.setCreateTime(currTime);
            opr.setUpdateAuthor("");
            opr.setUpdateTime(currTime);
            opr.setAccountId(accountId);
            opr.setIpAddress(ipaddress);
            opr.setRemark("");
            opr.setRoleId(roleId);
            opr.setProjectId(projectId);
            opr.setTenantId(tenantId);
            opr.setAppId(appId);

            this.iALoginOprDAO.insertLoginopr(opr);
        } else {
            list.size();
        }


        return mapOut;
    }


    private List<AuAccountRoleRel> selectAuAccountRoleRel(Account account, String projectId)
            throws Exception {
        String accountId = account.getId();
        List<AuAccountRoleRel> list = this.auAccountRoleRelDAO.select(accountId, projectId);
        return list;
    }


    private AuProjectRoleRel selectAuProjectRoleRel(String roleId, String projectId)
            throws Exception {
        AuProjectRoleRel RoleRel = this.iAuProjectRoleRelDAO.select(roleId, projectId);
        return RoleRel;
    }


    public List<AuRoleMenuAuth> getMenuAuthByParent(List<AuRoleMenuAuth> list)
            throws Exception {
        if (list == null) {
            return null;
        }
        for (AuRoleMenuAuth auth : list) {
            List<AuRoleMenuAuth> auths = getMenuAuthByParent(this.iAuRoleMenuAuthDAO.getAuRoleMenuAuthByParent(auth.getId()));
            if (auth.getResource() != null) {
                auth.setResource(this.resourceVersionDAO.select(auth.getResource().getId()));
            }
            auth.setChildrens(auths);
        }
        return list;
    }

    public String resolveJson(Map<String, Object> map) throws Exception {
        String json = (String) map.get("json");
        String projectId = (String) map.get("projectId");
        String appId = (String) map.get("appId");

        JSONObject jsonobject = JSONObject.parseObject(json);
        JSONArray jsonArray = (JSONArray) jsonobject.get("apps");
        if ((jsonArray != null) && (jsonArray.size() > 0)) {
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonobject1 = jsonArray.getJSONObject(i);
                if (appId.equals(jsonobject1.getString("id"))) {
                    this.accountApplicationDAO.updateStatus(appId, 1);
                    jsonobject1.put("status", Integer.valueOf(1));
                    jsonobject.put("type", jsonobject1.get("accountType"));
                    jsonobject.put("relationId", jsonobject1.get("accountRelationId"));
                } else if (1 == jsonobject1.getInteger("status").intValue()) {
                    this.accountApplicationDAO.updateStatus(jsonobject1.getString("id"), 2);
                    jsonobject1.put("status", Integer.valueOf(2));
                }
                if ("1".equals(jsonobject1.getString("systemFlag"))) {
                    JSONArray jsonArray1 = (JSONArray) jsonobject1.get("auProjectRoleRel");
                    if ((jsonArray1 != null) && (jsonArray1.size() > 0)) {
                        for (int j = 0; j < jsonArray1.size(); j++) {
                            if (projectId.equals(jsonArray1.getJSONObject(j).getString("projectId"))) {
                                jsonArray1.getJSONObject(j).put("selectStatus", Integer.valueOf(1));
                            } else if (1 == jsonArray1.getJSONObject(j).getInteger("selectStatus").intValue()) {
                                jsonArray1.getJSONObject(j).put("selectStatus", Integer.valueOf(2));
                            }
                        }
                    }
                }
            }
        }

        return jsonobject.toJSONString();
    }

    public AuHospital selectHospital(Tenant tenant)
            throws Exception {
        Map<String, Object> tempParam = new HashMap();
        tempParam.put("tenantId", tenant.getId());
        tempParam.put("status", "1");
        AuTenantDeptRel autent = qryAuTenantRel(tempParam);
        AuHospital auHospital = new AuHospital();

        if (autent != null) {
            String relationType = autent.getRelationType();

            if ("1".equals(relationType)) {
                tempParam.clear();
                tempParam.put("hospitalId", autent.getRelationId());
                auHospital = qryHospitalById(tempParam);
            } else if ("2".equals(relationType)) {
                tempParam.clear();
                tempParam.put("departmentId", autent.getRelationId());
                auHospital = qryHospitalByDepartmentId(tempParam);
            }
        }
        return auHospital;
    }

    public AuTenantDeptRel qryAuTenantRel(Map<String, Object> param) throws Exception {
        String tenantId = (String) param.get("tenantId");
        String status = "1";
        List<AuTenantDeptRel> list = this.auHospitalDao.selectTenantDeptRel(tenantId, status);
        if (!CollectionUtils.isEmpty(list)) {
            return (AuTenantDeptRel) list.get(0);
        }
        return null;
    }


    public AuHospital qryHospitalById(Map<String, Object> param)
            throws Exception {
        String hospitalId = (String) param.get("hospitalId");
        AuHospital hospital = this.auHospitalDao.selectHospital(hospitalId);
        return hospital;
    }

    public AuHospital qryHospitalByDepartmentId(Map<String, Object> param)
            throws Exception {
        String departmentId = (String) param.get("departmentId");
        AuHospital hospital = this.auHospitalDao.qryHospitalInfoByDepartmentId(departmentId);
        return hospital;
    }

    public Map<String, Object> modifyPassWord(String username, String password, String newPassword) throws Exception {
        Map<String, Object> map = new HashMap();
        password = ToolUtil.Encrept(password);
        newPassword = ToolUtil.Encrept(newPassword);
        List<Account> list = this.accountDAO.getAccountByUsername(username);
        if ((list != null) && (list.size() > 0)) {
            Account account = (Account) list.get(0);
            if (password.endsWith(account.getPassword())) {
                this.accountDAO.updatePassWord(newPassword, username);
            } else {
                throw new Exception("您输入的原始密码不正确~！");
            }
        } else {
            throw new Exception("账号错误或者不存在~！");
        }
        return map;
    }

}


